﻿using System;
using System.Diagnostics;

namespace GBricks
{
  using Properties;

  public interface IBlocker
  {
    bool IsBlocked { get; }
    IDisposable Block();
  }

  public static class Blocker
  {
    public static IBlocker Simple() {
      return new SimpleBlocker();
    }

    public static IBlocker Strong() {
      return new StrongBlocker();
    }

    public static IBlocker Counter() {
      return new CounterBlocker();
    }

    [DebuggerDisplay("{ IsBlocked ? \"Blocker\" : \"Unblocked\" }")]
    private sealed class SimpleBlocker : IBlocker
    {
      public bool IsBlocked { get; private set; }

      public IDisposable Block() {
        if(!IsBlocked) {
          IsBlocked = true;
          return Disposable.Create(() => IsBlocked = false);
        } else {
          return Disposable.Empty;
        }//if
      }
    }

    [DebuggerDisplay("{ IsBlocked ? \"Blocker\" : \"Unblocked\" }")]
    private sealed class StrongBlocker : IBlocker
    {
      public bool IsBlocked { get; private set; }

      public IDisposable Block() {
        if(IsBlocked) {
          throw ExceptionBuilder.InvalidOperation(Resources.LockerIsLocked);
        }//if

        IsBlocked = true;

        return Disposable.Create(() => {
          if(!IsBlocked) {
            throw ExceptionBuilder.InvalidOperation(Resources.LockerIsNotLocked);
          }//if

          IsBlocked = false;
        });
      }
    }

    [DebuggerDisplay("{ IsBlocked ? \"Blocked, \" + BlockCount + \" block(s)\": \"Unblocked\", nq }")]
    private sealed class CounterBlocker : IBlocker
    {
      private uint BlockCount { get; set; }

      public bool IsBlocked {
        [DebuggerStepThrough]
        get { return BlockCount > 0; }
      }

      public IDisposable Block() {
        BlockCount++;
        return Disposable.Create(() => BlockCount--);
      }
    }
  }
}
